#pragma once
#include <carbon/defs.h>
#include <cstddef>

CARBON_NS_BEGIN

/// @brief 一个容器对象可以表示包含的数据是否为Null。
/// @tparam T 值类型
template<typename T>
struct Optional {
    char    m_Data[sizeof(T)];  // 数据缓存，不是使用T类型，是为避免默认构造函数的调用消耗。
    bool    m_HasValue {false}; // 表示m_Data是否有效。当HasValue为true时，m_Data有效；HasValue为false时，m_Data必须是已经析构或未初始化的。

    Optional() noexcept {}

    explicit Optional(T&& value) : m_HasValue(true) {
        new (m_Data) T(std::move(value));
    }

    explicit Optional(const T& value) : m_HasValue(true) {
        new (m_Data) T(value);
    }

    Optional(const Optional & other );

    Optional(Optional && other ) noexcept : m_HasValue(other.m_HasValue) {
        if ( m_HasValue ) {
            new (m_Data) T(std::move(*reinterpret_cast<T*>(other.m_Data)));
            reinterpret_cast<T*>(other.m_Data)->~T();
            other.m_HasValue = false;
        }
    }

    ~Optional() noexcept { 
        if ( m_HasValue ) {
            reinterpret_cast<T*>(m_Data)->~T();
        }
        m_HasValue = false; 
    }

    Optional& operator=(const Optional & other);

    Optional& operator=(Optional && other) noexcept {
        if ( this == &other ) return *this;

        if ( this->m_HasValue ) {
            reinterpret_cast<T*>(m_Data)->~T(); // 本地有有效值，先析构
        }
        if ( other.m_HasValue ) { // other有有效值，先使用移动构造，other析构
            new (m_Data) T(std::move(*reinterpret_cast<T*>(other.m_Data)));
            reinterpret_cast<T*>(other.m_Data)->~T();
        }
        m_HasValue = other.m_HasValue;
        other.m_HasValue = false;
        return *this;
    }

    operator bool() const { return m_HasValue; }

    bool isPresent() const noexcept { return m_HasValue; }

    bool hasValue() const noexcept { return m_HasValue; }

    T& get() & noexcept { return *reinterpret_cast<T*>(m_Data); }
    const T& get() const& noexcept { return *reinterpret_cast<const T*>(m_Data);; }

    T&& get() && noexcept { return std::move(*reinterpret_cast<T*>(m_Data)); }

    const T&& get() const && noexcept { return std::move(*reinterpret_cast<const T*>(m_Data)); }

    T& orElse(T& other) & noexcept;
    const T& orElse(const T& other) const& noexcept;

    T&& orElse(T&& other) && noexcept;

    template <typename F>
    T orElseGet(F&& f) const& noexcept;

    template <typename F>
    T orElseGet(F&& f) && noexcept;

    template <typename F>
    void ifPresent(F&& f) const& noexcept;

    template <typename F>
    Optional filter(F&& f) const& noexcept;

    template <typename F>
    Optional filter(F&& f) && noexcept;

    template <typename U, typename F>
    Optional<U> map(F&& f) const& noexcept;

public:
    static Optional<T> empty() noexcept { return Optional<T>(); }  
    static Optional<T> of(T&& value) noexcept { return Optional<T>(std::move(value)); }
    static Optional<T> of(const T& value )noexcept { return Optional<T>(value); }

}; // Optional

CARBON_NS_END
